﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using OffInvoiceExcelAddIn.XmlMngFiles;
using OffInvoiceExcelAddIn.UBLFiles;
using OffInvoiceExcelAddIn.FacturaeFiles;
using System.Xml.Serialization;
using OffInvoiceExcelAddIn.CIIFiles;
using System.Xml;
using Xades;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;

namespace OffInvoiceExcelAddIn
{

    /// <summary>
    /// Clase que controla la emisión de una factura en cualquiera de los formatos
    /// </summary>
    class IssuedController
    {
        #region "Fields"


        /// <summary>
        /// Campo con la cultura para los numeros, fechas y moneda
        /// </summary>
        CultureInfo cInfo = null;

        /// <summary>
        /// Campo con el formato de los numeros de la factura
        /// </summary>
        FieldFormats ff = null;

        /// <summary>
        /// Campo con los calculos de la factura
        /// </summary>
        Calculos calculos = null;

        /// <summary>
        /// Campo con los datos introducidos por el usuario en la plantilla
        /// </summary>
        FacturaeFieldAndValues datos;

        #endregion

        #region "Contructors"

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="datos">Datos introducidos por el usuario</param>
        public IssuedController(FacturaeFieldAndValues datos)
        {
            cInfo = new CultureInfo(Globals.ThisAddIn.Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI));
            ff = new FieldFormats(cInfo, cInfo.NumberFormat, cInfo.Name);
            calculos = new Calculos(ff);
            this.datos = datos;
        }


        #endregion

        #region "Public Methods"

        /// <summary>
        /// Método que se encarga de la emisión de la factura.
        /// Primero se genera la factura, la valida y finalmente la firma
        /// </summary>
        /// <param name="path">Path de la factura</param>
        /// <param name="pathSignate">Path de la firma</param>
        /// <param name="configuration">Datos de la configuración</param>
        /// <param name="formatoFactura">Formato de la factura</param>
        public void issuedInvoice(string path, string pathSignate, ConfigData configuration, int formatoFactura)
        {
            ControlMessages msg = ControlMessages.getInstance();
            FrmProgressBar f = new FrmProgressBar();
            try
            {
                f.Show();
                f.setMessage(msg.getMessage("GeneratedSchema"));
                if (formatoFactura.Equals(InvoiceTypes.FACTURAE_3_1))
                {
                    generateInvoice(path, false, InvoiceTypes.FACTURAE_3_1);

                }
                else if (formatoFactura.Equals(InvoiceTypes.FACTURAE_3_2))
                {
                    generateInvoice(path, false, InvoiceTypes.FACTURAE_3_2);

                }
                else if (formatoFactura.Equals(InvoiceTypes.UBL))
                {
                    generateInvoice(path, false, InvoiceTypes.UBL);

                }
                else if (formatoFactura.Equals(InvoiceTypes.CII))
                {
                    generateInvoice(path, false, InvoiceTypes.CII);

                }
                f.setMessage(msg.getMessage("AccountValidation"));
                ValidateController v = new ValidateController();
                v.AccountingValidation(path, false, formatoFactura);
                f.setMessage(msg.getMessage("Signed"));
                signateInvoice(path, pathSignate, configuration, f);
                f.Close();

            }

            catch (Exception e)
            {
                f.Close();
                throw e;
            }
        }

        /// <summary>
        /// Método que genera la facura
        /// </summary>
        /// <param name="path">Parámetro de tipo string con el path de la factura</param>
        /// <param name="paperInvoice">Parámetro de tipo bool que indica si la factura es en papel</param>
        /// <param name="invoiceType">Tipo de factura</param>
        public void generateInvoice(string path, bool paperInvoice, int invoiceType)
        {

            try
            {
                

                if (invoiceType.Equals(InvoiceTypes.FACTURAE_3_1))
                {

                    FacturaeGenerator generator = new FacturaeGenerator(new Facturae(), Globals.ThisAddIn.Application.ActiveSheet, paperInvoice, InvoiceTypes.FACTURAE_3_1, calculos, datos);
                    Facturae facturae = generator.getFacturae();

                    XmlRootAttribute rootAttribute = new XmlRootAttribute();
                    rootAttribute.Namespace = "http://www.facturae.es/Facturae/2007/v3.1/Facturae";
                    rootAttribute.IsNullable = false;

                    XmlSerializer serializer = new XmlSerializer(typeof(Facturae), rootAttribute);
                    System.IO.StreamWriter w = new System.IO.StreamWriter(path);

                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("namespace", "http://www.facturae.es/Facturae/2007/v3.0/Facturae");
                    ns.Add("", "http://www.facturae.es/Facturae/2007/v3.1/Facturae");
                    ns.Add("namespace2", "http://uri.etsi.org/01903/v1.3.2#");
                    ns.Add("namespace3", "http://www.w3.org/2000/09/xmldsig#");

                    serializer.Serialize(w, facturae, ns);
                    w.Close();
                }
                else if (invoiceType.Equals(InvoiceTypes.FACTURAE_3_2))
                {

                    FacturaeGenerator generator = new FacturaeGenerator(new Facturae(), Globals.ThisAddIn.Application.ActiveSheet, paperInvoice, InvoiceTypes.FACTURAE_3_2, calculos, datos);
                    Facturae facturae = generator.getFacturae();

                    XmlRootAttribute rootAttribute = new XmlRootAttribute();
                    rootAttribute.Namespace = "http://www.facturae.es/Facturae/2009/v3.2/Facturae";
                    rootAttribute.IsNullable = false;

                    XmlSerializer serializer = new XmlSerializer(typeof(Facturae), rootAttribute);
                    System.IO.StreamWriter w = new System.IO.StreamWriter(path);

                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("namespace", "http://www.facturae.es/Facturae/2007/v3.0/Facturae");
                    ns.Add("", "http://www.facturae.es/Facturae/2009/v3.2/Facturae");
                    ns.Add("namespace2", "http://uri.etsi.org/01903/v1.3.2#");
                    ns.Add("namespace3", "http://www.w3.org/2000/09/xmldsig#");

                    serializer.Serialize(w, facturae, ns);
                    w.Close();
                }
                else if (invoiceType.Equals(InvoiceTypes.UBL))
                {
                    UBLGenerator ubl = new UBLGenerator(datos);
                    XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
                    System.IO.StreamWriter w = new System.IO.StreamWriter(path);

                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("qdt", "urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2");
                    ns.Add("ccts", "urn:oasis:names:specification:ubl:schema:xsd:CoreComponentParameters-2");
                    ns.Add("stat", "urn:oasis:names:specification:ubl:schema:xsd:DocumentStatusCode-1.0");
                    ns.Add("cbc", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
                    ns.Add("cac", "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2");
                    ns.Add("udt", "urn:un:unece:uncefact:data:draft:UnqualifiedDataTypesSchemaModule:2");
                    ns.Add("", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");

                    serializer.Serialize(w, ubl.Invoice, ns);
                    w.Close();

                }
                else if (invoiceType.Equals(InvoiceTypes.CII))
                {
                    CIIGenerator cii = new CIIGenerator(datos);
                    XmlSerializer serializer = new XmlSerializer(typeof(CrossIndustryInvoice));
                    System.IO.StreamWriter w = new System.IO.StreamWriter(path);

                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:7");
                    ns.Add("udt", "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:8");
                    ns.Add("qdt", "urn:un:unece:uncefact:data:standard:QualifiedDataType:7");
                    ns.Add("ccts", "urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2");
                    ns.Add("", "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:1");

                    serializer.Serialize(w, cii.Invoice, ns);
                    w.Close();
                }

            }
            catch (Exception e)
            {
                throw e;
            }

        }

        /// <summary>
        /// Método igual que el de emitir pero sin firmar.
        /// </summary>
        /// <param name="path">Parámetro de tipo string con el path de la factura</param>
        /// <param name="configuration">Parámetro de tipo ConfigData referenciando a la configuración definida por el usuario</param>
        public void cerrarFactura(string path, ConfigData configuration)
        {
            try
            {
                generateInvoice(path, true, InvoiceTypes.FACTURAE_3_1);
                ValidateController v = new ValidateController();
                v.AccountingValidation(path, false, InvoiceTypes.FACTURAE_3_1);
            }
            catch (Exception e)
            {
                throw e;
            }

        }

        /// <summary>
        /// Método que se encarga de firmar la factura
        /// </summary>
        /// <param name="pathDocBeforeSignature">Parámetro de tipo string con el path de antes de firmar</param>
        /// <param name="pathDocAfterSignature">Parámetro de tipo string con el path de despues de firmar</param>
        /// <param name="configuration">Parámetro de tipo ConfigData referenciando a la configuración definida por el usuario</param>
        /// <param name="f">Parámetro de tipo FrmProgressBar referencia a la barra de progreso que se muestra mientras se está generando la factura.</param>
        public void signateInvoice(string pathDocBeforeSignature, string pathDocAfterSignature, ConfigData configuration, FrmProgressBar f)
        {
            try
            {
                string urlTSA = "http://timestamping.edelweb.fr/service/tsp";
                if (configuration != null)
                {
                    urlTSA = configuration.UrlSTServer;
                }
                XmlDocument doc = new XmlDocument();
                doc.PreserveWhitespace = true;
                doc.Load(pathDocBeforeSignature);
                string role = Globals.ThisAddIn.GetControlValue(ControlList.Tag.InvoiceIssuerType);
                XadesSignature xadesSignature = new XadesSignature();
                if (configuration.SignedType.Equals("XADES-XL"))
                {
                    try
                    {
                        //xadesSignature.XadesXL(doc, role, urlTSA, Const.APPLICATION);
                        xadesSignature.XadesXL(doc, role,urlTSA, configuration.UserNameSTServer, configuration.PassworSTServer,Const.APPLICATION);


                    }
                    catch (Exception ex)
                    {
                        if (ex.Message.Equals("ErroCRLOCSPNotFound"))
                        {
                            ControlMessages msg = ControlMessages.getInstance();
                            if (MessageBox.Show(msg.getMessage(ControlMessages.Msg.ErroCRLOCSPNotFound), msg.getMessage(ControlMessages.Msg.CaptionFacturae), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                            {
                                doc = new XmlDocument();
                                doc.PreserveWhitespace = true;
                                doc.Load(pathDocBeforeSignature);
                                xadesSignature.XadesEpes(doc, role, Const.APPLICATION);
                            }
                            else
                            {
                                throw new Exception("NotSigned");
                            }
                        }
                        else
                        {
                            throw ex;
                        }
                    }

                }
                else
                {
                    xadesSignature.XadesEpes(doc, role, Const.APPLICATION);
                }
                try
                {
                    f.setMessage("Realizando validación ...");
                    xadesSignature.XadesValidation(doc, false);

                }
                catch (Exception e)
                {
                    throw e;
                }


                doc.Save(pathDocAfterSignature);


            }
            catch (Exception ex)
            {
                if (!ex.Message.Equals("ErrorCheckSignature") && !ex.Message.Equals("ErrorCertificateNull") && !ex.Message.Equals("NotSigned"))
                {
                    ControlMessages msg = ControlMessages.getInstance();
                    string error = msg.getMessage("ErrorDocNotSigned") + "  -" + msg.getMessage(ex.Message);
                    throw new Exception(error);
                }
                else
                    throw ex;
            }
        }

        #endregion
    }
}
